﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace TemplateHelper
{
    public class Tmp
    {
        public void Test()
        {
            var generator = new GenericsGenerator(4);
            generator.InputTypes.Select(i => string.Format("public {0} {1} => _inputRow.{1};", i.TypeName, i.PropertyName));
            generator.InputTypes.Select(input => string.Format("testCase.{0} #>", input.PropertyName), ", ");
        }
    }

    public class GenericsGenerator
    {
        private const string InputTypeBase = "TIn";
        private const string DefaoultOutputType = "TOut";

        private readonly int _inputs;

        public TypeCollection InputTypes { get; }

        public TypeCollection AllTypes { get; }

        public TypeDeclaration OutputType { get; }

        public GenericsGenerator(int inputs)
            : this(inputs, DefaoultOutputType)
        {                  
        }

        public GenericsGenerator(int inputs, string outputType)            
        {
            _inputs = inputs;
            InputTypes = TypeCollection.Inputs(inputs);
            OutputType = TemplateHelper.TypeDeclaration.FromTypeName(outputType);

            AllTypes = TypeCollection.Inputs(inputs, OutputType);            
        }

        public string TypeDefinition()
        {
            return AllTypes.CreateDefinition();
        }

        public string TypeDefinition(params string[] additionalTypeNames)
        {
            return AllTypes.CreateDefinition(additionalTypeNames);                
        }

        public string TypeDeclaration(string outputTypeName)
        {
            var outputType = TemplateHelper.TypeDeclaration.FromTypeName(outputTypeName);            
            var augmentedCollection = InputTypes.Append(outputType);
            return augmentedCollection.CreateDefinition();
        }

        public string InputDefinition()
        {
            return InputTypes.CreateDefinition();
        }

        public string InputDefinition(params string[] additionalTypeNames)
        {
            return InputTypes.CreateDefinition(additionalTypeNames);            
        }
      
        public string InputArgumentDeclaration()
        {
            return string.Join(", ", GetInputArgumentDeclarations());
        }

        public string InputArguments()
        {
            return string.Join(", ", GetInputArguments());
        }

        public string InputProperties(int indents = 0)
        {            
            return string.Join(Environment.NewLine, GetInputProperties(Indent(indents)));
        }         

        private IEnumerable<string> GetInputArgumentDeclarations()
        {
            for (int i = 1; i <= _inputs; i++)
            {
                yield return $"{InputTypeBase}{i} in{i}";
            }
        }

        private IEnumerable<string> GetInputArguments()
        {
            for (int i = 1; i <= _inputs; i++)
            {
                yield return $"in{i}";
            }
        }

        private IEnumerable<string> GetInputProperties(string indent)
        {
            for (int i = 1; i <= _inputs; i++)
            {
                yield return $"{indent}public {InputTypeBase}{i} In{i} {{ get; }}";
            }
        }

        private string Indent(int indents)
        {
            return new string('\t', indents);
        }
    }
}
